#include <iostream>

/*说明*/
/*
 * 1、在构造函数中调用virtual函数会出现一个问题：构造函数实现顺序是从基类到派生类，如果基类构造函数调用了虚函数：
 *    1）纯虚函数：这时候派生类还没有开始构造，所以还没有重写的虚函数提供调用，这时候编译器会报错。
 *    2）非纯虚函数：如果基类自己有对虚函数的实现，但在基类初始化的时候，派生类还没有开始构造，相关变量也没有初始化，
 *      这时候调用的虚函数是基类的实现，而不是派生类的重写实现，这时候程序的行为是错误的。
 * 2、在析构函数中调用virtual函数会出现一个问题：析构函数实现顺序是从派生类到基类，当基类开始析构的时候，派生类的相关变量已经被析构，
 *    这时候调用的虚函数是基类的实现，而不是派生类的重写实现，或者使用到的相关变量已经被析构，会出现未定义行为，程序崩溃。
 **/


/*
*
* 正确做法
* 1、在构造函数中不使用virtual函数
* 2、将派生类的日志记录传给基类构造函数中，通过基类构造函数调用日志记录函数记录日志
* 3、派生类最好的做法是将日志记录传给基类构造函数，最好是使用一个函数来传递，不要使用初始化列表，这样可读性更好。需要注意的是，
*    这个传递函数应该是静态的，这样可以确保在基类构造函数中调用之前，派生类已经完成了日志记录的初始化。
*/

//原文使用了打印交易日志的例子

class Transaction {
public:
    explicit Transaction(const std::string &message) {
        std::cout << "Transaction created" << std::endl;
        logTransaction(message);
    }
    void logTransaction(const std::string &message)const {  
          std::cout << "Transaction logTransaction" << message << std::endl;
    }

    virtual ~Transaction() {
        std::cout << "Transaction destroyed" << std::endl;
    }


};

class BuyTransaction : public Transaction { //继承Transaction
public:
    BuyTransaction(std::string symbol, int shares, double price) : m_symbol(symbol), m_shares(shares), m_price(price),Transaction(createLogMessage(symbol)) {
        std::cout << "BuyTransaction created" << std::endl;
    }
    ~BuyTransaction() {
        std::cout << "BuyTransaction destroyed" << std::endl;
    }

private:
    static std::string& createLogMessage(std::string& symbol) {
        static std::string message;
        message = "BuyTransaction logged " + symbol;
        return message;
    }
    std::string m_symbol;
    int m_shares;
    double m_price;

};

int main(int argc, char const *argv[])
{
    
    BuyTransaction buyTransaction("buy", 100, 10.0); //创建BuyTransaction对象  如果logTransaction()是纯虚函数，编译器会报错  
                                    //如果logTransaction()是非纯虚函数，打印的日志是基类的实现，而不是派生类的重写实现

    
    return 0;
}
